package edu.umn.msse.farside.FourH.services.impl;

import edu.umn.msse.farside.FourH.domain.Event;
import edu.umn.msse.farside.FourH.domain.Position;
import edu.umn.msse.farside.FourH.domain.Volunteer;
import edu.umn.msse.farside.FourH.services.EventService;
import org.springframework.orm.jpa.JpaTemplate;
import org.springframework.orm.jpa.support.JpaDaoSupport;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * Created by IntelliJ IDEA.
 * User: corcutt
 * Date: Feb 10, 2009
 * Time: 6:34:09 PM
 * Services to handle CRUD of Events
 * Services to handle retrievel of Events data, including the position(s) for the event
 */
public class EventServiceImpl extends JpaDaoSupport implements EventService
{
    /**
     * Create of an event in the database
     *
     * @param event The event to be added to the repository
     */
    public void addEvent(Event event)
    {
        if (event.getId() != null) {
            throw new IllegalArgumentException("Not a new event.");
        }

        getJpaTemplate().persist(event);
        getJpaTemplate().flush();
    }

    /**
     * Retrieve an event from the repository
     *
     * @param event The event name
     * @return an event retrieved from the repository
     */
    public Event getEvent(Event event)
    {
        if (event == null || event.getId() == null ) {
            throw new IllegalArgumentException("Not an existing event.");
        }
        JpaTemplate jpa = getJpaTemplate();
        Event currentEvent = jpa.find(Event.class, event.getId());
        return currentEvent;
    }

    /**
     * Retrieve an event from the repository
     * @param id The event id
     * @return an event retrieved from the repository
     */
    public Event getEvent(Long id)
    {
        if (id == null)
        {
            throw new IllegalArgumentException("Null id");
        }

        JpaTemplate jpa = getJpaTemplate();
        Event currentEvent = jpa.find(Event.class, id);

        return currentEvent;
    }

    /**
     * Retrieve a position from the repository
     * @param id The Position id
     * @return a position retrieved from the repository
     */
    public Position getPosition(Long id)
    {
        if (id == null)
        {
            throw new IllegalArgumentException("Null id");
        }

        JpaTemplate jpa = getJpaTemplate();
        Position position = jpa.find(Position.class, id);

        return position;
    }

    /**
     * Retrieve all events from the repository
     *
     * @return an event retrieved from the repository
     */
    public List getEvents()
    {
        return getJpaTemplate().find("select distinct(e) from Event e");
    }


    /**
     * Remove information about an event and its position(s)
     *
     * @param event The event to be removed
     */
    public void removeEvent(Event event)
    {
        if (event.getId() == null) {
            throw new IllegalArgumentException("Not an existing event.");
        }

        JpaTemplate jt = getJpaTemplate();
        jt.remove(jt.contains(event) ? event : jt.merge(event));
    }


    /**
     * Add positions to the event
     * @param event   The event to add positions to
     * @param positions The position(s) to add to the event
     */
    
    public void addPositions(Event event, List<Position> positions)
    {
        if (event.getId() == null) {
            throw new IllegalArgumentException("Not an existing event.");
        }

        JpaTemplate jt = getJpaTemplate();
        Event currentEvent = jt.find(Event.class,event.getId());
        currentEvent.addPositions(positions);
        currentEvent = jt.merge(currentEvent);
        jt.persist(currentEvent);
    }

    /**
     * Add positions to the event
     * @param event   The event to add positions to
     * @param position The position(s) to add to the event
     */

    public void addPosition(Event event, Position position)
    {
        if (event.getId() == null) {
            throw new IllegalArgumentException("Not an existing event.");
        }

        JpaTemplate jt = getJpaTemplate();
        Event currentEvent = jt.find(Event.class,event.getId());
        currentEvent.addPosition(position);
        currentEvent = jt.merge(currentEvent);
        jt.persist(currentEvent);
    }


    /**
     * remove the position from the event
     * Positions can only be removed if they have no volunteers.
     * @param event  The event to remove the position from
     * @param position  The position to remove
     */
    public void removePosition(Event event, Position position) {
        if (event.getId() == null) {
            throw new IllegalArgumentException("Not an existing event.");
        }
        JpaTemplate jt = getJpaTemplate();
        Event currentEvent = jt.find(Event.class,event.getId());
        currentEvent.removePosition(position);

        currentEvent = jt.merge(currentEvent);
        jt.persist(currentEvent);
        getJpaTemplate().flush();
    }


    /**
     * Update information about the event
     * @param event  The event to be updated
     */
    public Event updateEvent(Event event)
    {
        if (event.getId() == null) {
            throw new IllegalArgumentException("Not an existing event.");
        }

        JpaTemplate jt = getJpaTemplate();
        event = jt.merge(event);
        jt.flush();
        return event;
    }

    /**
     * Update information about an Position and its position
     * @param position The Position to be updated
     */
    public Position updatePosition(Position position)
    {
         if (position.getId() == null) {
             throw new IllegalArgumentException("Not an existing position.");
         }

         JpaTemplate jt = getJpaTemplate();
         position = jt.merge(position);
         jt.flush();
         return position;
     }

    /**
     * Provide a list of all future events in the repository
     *
     * @return a list of all future events in the repository
     */
    public Collection<Event> listActiveEvents()
    {
        //long today = System.currentTimeMillis();
        java.util.Date today = new java.util.Date();
        Timestamp todayTimestamp = new java.sql.Timestamp(today.getTime());
        return getJpaTemplate().find("select distinct(e) from Event e where e.endDateAndTime > ?", todayTimestamp);
    }

    /**
     * Provide a list of all events created by the user.
     * @param volunteer
     * @return
     */
    public List<Event> getEventsForUser(Volunteer volunteer)
    {
        return getJpaTemplate().find("select distinct(e) from Event e where e.administrator = ? ", volunteer );
    }


    /**
     * Provide a list of all positions for an event
     *
     * @param event
     * @return a list of all positions for the given event
     */
    public Collection<Position> listAllPositions(Event event)
    {
        //List<Position> positions = getJpaTemplate().find(Event.class, event.getId()).getEventPositions();
        //return positions;

        List<Event> currentEvent = getJpaTemplate().find(
                "select distinct(e) from Event e join e.eventPositions p where " +
                "e.id  = ?", event.getId());
        if (currentEvent.size() > 0)
        {
            return currentEvent.get(0).getEventPositions();
        }
        else
        {
            return event.getEventPositions();
        }
    }

    /**
     * Provide a list of all filled positions of an event
     *
     * @param event
     * @return list of all filled positions for the given event
     */
    public Collection<Position> listFilledPositions(Event event)
    {
        List<Event> currentEvent = getJpaTemplate().find(
                "select distinct(e) from Event e join e.eventPositions p where " +
                "e.id  = ?", event.getId());
        List<Position> filledPositions = new ArrayList<Position>();
        for(Position p : currentEvent.get(0).getEventPositions()) {
            if(p.getVolunteers().size() == p.getNumberOfVolunteers()) {
                filledPositions.add(p);
            }
        }

        return filledPositions;
    }

    /**
     * Provide a list of all open (unfilled) positions of an event
     *
     * @param event
     * @return list of all open positions for the given event
     */
    public Collection<Position> listUnfilledPositions(Event event)
    {
        List<Event> currentEvent = getJpaTemplate().find(
                "select distinct(e) from Event e where " +
                "e.id  = ?", event.getId());
        List<Position> unfilledPositions = new ArrayList<Position>();
        for(Position p : currentEvent.get(0).getEventPositions()) {
            if(p.getVolunteers().size() < p.getNumberOfVolunteers()) {
                unfilledPositions.add(p);
            }
        }

        return unfilledPositions;

    }

}
